package Circle;

use strict;
use warnings;

sub new {
   my $package = shift;
   my ($x_m, $y_m, $r) = @_;

   my $self = {
      x_m  => $x_m,
      y_m  => $y_m,
      r    => $r,
   };

   return bless $self, $package;
}


=head1 Tangent lines

=head2 Tangent lines in a given direction

   my ($x1, $y1, $x2, $y2) =
     $circle -> tangent_in_direction ( $d_x, $d_y );

or

   my ($x_t, $y_t) =
     $circle -> tangent_in_direction ( $d_x, $d_y, $x, $y );

There are always two lines in the direction C<(d_x,d_y)> tangent to the circle.
This function calculates the points where the tangent lines touch the circle.

The lines from the midpoint of the circle to the points are perpendicular to
the tangent lines and have length C<r>.

The function takes two or four arguments.

If two arguments are given, they are assumed to be the direction vector of the
tangent line. The returned values are the coordinate pairs of the
tangent points.

If four arguments are given, the last two are coordinates. The
solution nearest to this point are returned.


=cut

sub tangent_in_direction {
   my $self = shift;
   my ($d_x, $d_y, $x, $y) = @_;

   my $l = sqrt ($d_x * $d_x + $d_y + $d_y);

   # first ray is ($r_x, $r_y); second ray is (-$r_x, -$r_y).
   my $r_x =   $d_y * $self -> {'r'} / $l;
   my $r_y = - $d_x * $self -> {'r'} / $l;


   if (defined $x and defined $y) {
      # if a point is defined, find which of the two solutions is on the 'side'
      # of the given point by determining the dot product

      if ( ($r_x * ($x - $self -> {'x_m'}) +
            $r_y * ($y - $self -> {'y_m'})    ) >= 0) {

         # point is on the same 'side' as the ray
         return ($self -> {'x_m'} + $r_x, $self -> {'y_m'} + $r_y);
      }
      else {

         # point is on the wrong side; return the other solution
         return ($self -> {'x_m'} - $r_x, $self -> {'y_m'} - $r_y);
      }
   }
   else {
      # otherwise, return both points
      return ($r_x, $r_y, -$r_x, -$r_y);
   }
}

=head2 Tangent line through a point

=cut

sub tangent_through_point {
   my $self = shift;
   my ($p_x, $p_y, $x, $y) = @_;




# module OK
1;

